package com.hk.core.jdbc.query;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hk.commons.query.QueryModel;
import com.hk.commons.util.StringUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.*;

/**
 * @author kevin
 * @date 2019-8-30 11:06
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class ConditionQueryModel extends QueryModel<CompositeCondition> {

    public ConditionQueryModel() {
        setParam(new CompositeCondition());
    }

    /**
     * 将对象的属性转换为 Map ，方便 {@link  com.hk.core.jdbc.deserializer.ConditionQueryModelDeserializer} 能再次序列化成此对象.
     * <p>
     * 对于 Jackson 库,也支持使用 {@link com.hk.core.jdbc.serializer.ConditionQueryModelSerializer} 进行序列化，
     * 需要在 {@link com.fasterxml.jackson.databind.ObjectMapper} 中配置此序列化，在 Spring web 或Spring webflux中默认有配置，
     * 参考 {@link com.hk.core.autoconfigure.web.WebContextConfiguration.JacksonJdbcSupportUtils}
     * <p>
     * 对于 {@link  org.springframework.web.reactive.function.client.WebClient}，
     * 参考 {@link com.hk.core.autoconfigure.web.reactive.ReactiveCustomConfigurer#defaultWebClient(WebClient.Builder, ObjectMapper)} ()}
     * 中的 配置Jackson 编码解码器
     */
    public Map<String, Object> toMap() {
        Map<String, Object> result = new HashMap<>();
        result.put("pageIndex", getPageIndex());
        result.put("pageSize", getPageSize());
        result.put("orders", getOrders());
        Map<String, Object> param = new HashMap<>();
        CompositeCondition condition = getParam();
        result.put("andOr", condition.getAndOr().toString());
        List<Condition> conditions = condition.getConditions();
        List<Map<String, Object>> simpleConditions = new ArrayList<>();
        List<Map<String, Object>> dateRangeConditions = new ArrayList<>();
        List<Map<String, Object>> rangeConditions = new ArrayList<>();
        for (Condition item : conditions) {
            if (item instanceof SimpleCondition simpleCondition) {
                simpleConditions.add(generatorSimpleMap(simpleCondition));
            } else if (item instanceof DateRangeCondition dateRangeCondition) {
                dateRangeConditions.add(generatorDateRangeMap(dateRangeCondition));
            } else if (item instanceof RangeCondition<?> rangeCondition) {
                rangeConditions.add(generatorRangeMap(rangeCondition));
            }
        }
        if (!simpleConditions.isEmpty()) {
            param.put("simple", simpleConditions);
        }
        if (!dateRangeConditions.isEmpty()) {
            param.put("dateRange", dateRangeConditions);
        }
        if (!rangeConditions.isEmpty()) {
            param.put("range", rangeConditions);
        }
        result.put("param", param);
        return result;
    }

    private Map<String, Object> generatorRangeMap(RangeCondition<?> condition) {
        Map<String, Object> rangeConditionMap = HashMap.newHashMap(5);
        rangeConditionMap.put("field", condition.getField());
        rangeConditionMap.put("includeStart", condition.isIncludeStart());
        rangeConditionMap.put("includeEnd", condition.isIncludeEnd());
        if (Objects.nonNull(condition.getStart())) {
            rangeConditionMap.put("start", condition.getStart());
        }
        if (Objects.nonNull(condition.getEnd())) {
            rangeConditionMap.put("end", condition.getEnd());
        }
        return rangeConditionMap;
    }

    private Map<String, Object> generatorDateRangeMap(DateRangeCondition condition) {
        Map<String, Object> dateRangeConditionMap = HashMap.newHashMap(4);
        dateRangeConditionMap.put("field", condition.getField());
        if (Objects.nonNull(condition.getRange())) {
            dateRangeConditionMap.put("range", condition.getRange().toString());
        }
        if (StringUtils.hasLength(condition.getStart())) {
            dateRangeConditionMap.put("start", condition.getStart());
        }
        if (StringUtils.hasLength(condition.getEnd())) {
            dateRangeConditionMap.put("end", condition.getEnd());
        }
        return dateRangeConditionMap;
    }

    private Map<String, Object> generatorSimpleMap(SimpleCondition condition) {
        Map<String, Object> simpleConditionMap = HashMap.newHashMap(3);
        simpleConditionMap.put("field", condition.getField());
        if (Objects.nonNull(condition.getOperator())) {
            simpleConditionMap.put("operator", condition.getOperator().toString());
        }
        if (Objects.nonNull(condition.getValue())) {
            simpleConditionMap.put("value", condition.getValue());
        }
        return simpleConditionMap;
    }
}
